package logmanager

import (
	"context"
	"errors"
	"time"

	"dev.ixmxm.top/rms/boot"
	"dev.ixmxm.top/rms/codes"
	"dev.ixmxm.top/rms/model"
	"dev.ixmxm.top/rms/utils/log"
	"dev.ixmxm.top/rms/utils/page"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func NewLogManager(db *boot.MongoDB) *LogManager {
	rm := &LogManager{db: db}
	return rm
}

type LogManager struct {
	db           *boot.MongoDB
	SystemConfig *model.SystemConfig //系统配置(缓存),不可直接赋值保存，调用SaveSystemConfigToCache保存
}

//AddRMSLogToDB 添加rms日志到数据库
func (m *LogManager) AddRMSLogToDB(ctx context.Context, l *model.RMSLog) codes.Code {
	l.CreatedAt = time.Now()
	_, errInsert := m.db.Collection(ctx, l.TableName()).InsertOne(ctx, l)
	if errInsert != nil {
		log.ErrorfWithContext(ctx, "insert rms log to db error:%s", errInsert.Error())
		return codes.ErrDatabase.Wrap(errInsert)
	}
	return nil
}

//AddRobotLogToDB 添加robot日志到数据库
func (m *LogManager) AddRobotLogToDB(ctx context.Context, l *model.RobotLog) codes.Code {
	l.CreatedAt = time.Now()
	_, errInsert := m.db.Collection(ctx, l.TableName()).InsertOne(ctx, l)
	if errInsert != nil {
		log.ErrorfWithContext(ctx, "insert robot log to db error:%s", errInsert.Error())
		return codes.ErrDatabase.Wrap(errInsert)
	}
	return nil
}

//删除所有的RMS日志
func (m *LogManager) DeleteAllRMSLogsFromDB(ctx context.Context) codes.Code {

	_, err := m.db.Collection(ctx, model.RMSLog{}.TableName()).DeleteMany(ctx, bson.D{})
	if err != nil {
		log.ErrorfWithContext(ctx, "clear all rms logs from db. error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}
	return nil
}

//删除所有的机器人日志
func (m *LogManager) DeleteAllRobotLogsFromDB(ctx context.Context) codes.Code {

	_, err := m.db.Collection(ctx, model.RobotLog{}.TableName()).DeleteMany(ctx, bson.D{})
	if err != nil {
		log.ErrorfWithContext(ctx, "clear all agv logs from db. error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}
	return nil
}

//GetRMSLogsForPageFromDB 从数据库获得rms日志，并分页
func (m *LogManager) GetRMSLogsForPageFromDB(ctx context.Context, from, end time.Time, minLevel uint8, pageParam page.Params) ([]model.RMSLog, page.PageResult, codes.Code) {
	page.SetPageParams(&pageParam.PageSize, &pageParam.PageIndex, 20)
	if end.IsZero() {
		end = time.Now()
	}
	filter := bson.M{"created_at": bson.M{"$gte": from, "$lte": end}, "level": bson.M{"$gte": minLevel}}
	total, errCount := m.db.Collection(ctx, model.RMSLog{}.TableName()).CountDocuments(ctx, filter)
	if errCount != nil {
		log.ErrorfWithContext(ctx, "count rms logs error:%s", errCount.Error())
		return nil, page.PageResult{}, codes.ErrDatabase.Wrap(errCount)
	}
	skip := (pageParam.PageIndex - 1) * pageParam.PageSize
	dbRes, err := m.db.Collection(ctx, model.RMSLog{}.TableName()).Find(ctx, filter, &options.FindOptions{Skip: &skip, Limit: &pageParam.PageSize, Sort: bson.M{"created_at": -1}})
	if err != nil {
		log.ErrorfWithContext(ctx, "get rms logs from db error:%s", err.Error())
		return nil, page.PageResult{}, codes.ErrDatabase.Wrap(err)
	}
	logs := make([]model.RMSLog, 0)
	if errBind := dbRes.All(ctx, &logs); errBind != nil {
		log.ErrorfWithContext(ctx, "bind rms logs from db error:%s", errBind.Error())
		return nil, page.PageResult{}, codes.ErrDatabase.Wrap(errBind)
	}
	return logs, page.NewPageResult(pageParam.PageSize, pageParam.PageIndex, total), nil
}

//获得即将导出的RMS日志，按照起终止时间和等级
func (m *LogManager) GetExportRMSLogsFromDB(ctx context.Context, from, end time.Time, minLevel uint8) ([]model.RMSLog, codes.Code) {
	if end.IsZero() {
		end = time.Now()
	}
	filter := bson.M{"created_at": bson.M{"$gte": from, "$lte": end}, "level": bson.M{"$gte": minLevel}}
	dbRes, err := m.db.Collection(ctx, model.RMSLog{}.TableName()).Find(ctx, filter)
	if err != nil {
		log.ErrorfWithContext(ctx, "get robot logs from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(err)
	}
	logs := make([]model.RMSLog, 0)
	if errBind := dbRes.All(ctx, &logs); errBind != nil {
		log.ErrorfWithContext(ctx, "bind robot logs from db error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return logs, nil
}

//获得即将导出的机器人日志，按照起终止时间和等级
func (m *LogManager) GetExportRobotsLogsFromDB(ctx context.Context, from, end time.Time, agvID string) ([]model.RobotLog, codes.Code) {
	if end.IsZero() {
		end = time.Now()
	}
	filter := bson.M{"created_at": bson.M{"$gte": from, "$lte": end}}
	if agvID != "" {
		filter["agv_id"] = agvID
	}
	dbRes, err := m.db.Collection(ctx, model.RobotLog{}.TableName()).Find(ctx, filter)
	if err != nil {
		log.ErrorfWithContext(ctx, "get robot logs from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(err)
	}
	logs := make([]model.RobotLog, 0)
	if errBind := dbRes.All(ctx, &logs); errBind != nil {
		log.ErrorfWithContext(ctx, "bind robot logs from db error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return logs, nil
}

//GetRobotsLogsForPageFromDB 从数据库获得机器人日志，并分页
func (m *LogManager) GetRobotsLogsForPageFromDB(ctx context.Context, from, end time.Time, agvID string, pageParam page.Params) ([]model.RobotLog, page.PageResult, codes.Code) {
	page.SetPageParams(&pageParam.PageSize, &pageParam.PageIndex, 20)
	if end.IsZero() {
		end = time.Now()
	}
	skip := (pageParam.PageIndex - 1) * pageParam.PageSize
	filter := bson.M{"created_at": bson.M{"$gte": from, "$lte": end}}
	if agvID != "" {
		filter["agv_id"] = agvID
	}
	total, errCount := m.db.Collection(ctx, model.RobotLog{}.TableName()).CountDocuments(ctx, filter)
	if errCount != nil {
		log.ErrorfWithContext(ctx, "count robot logs error:%s", errCount.Error())
		return nil, page.PageResult{}, codes.ErrDatabase.Wrap(errCount)
	}
	dbRes, err := m.db.Collection(ctx, model.RobotLog{}.TableName()).Find(ctx, filter, &options.FindOptions{Skip: &skip, Limit: &pageParam.PageSize, Sort: bson.M{"created_at": -1}})
	if err != nil {
		log.ErrorfWithContext(ctx, "get robot logs from db error:%s", err.Error())
		return nil, page.PageResult{}, codes.ErrDatabase.Wrap(err)
	}
	logs := make([]model.RobotLog, 0)
	if errBind := dbRes.All(ctx, &logs); errBind != nil {
		log.ErrorfWithContext(ctx, "bind robot logs from db error:%s", errBind.Error())
		return nil, page.PageResult{}, codes.ErrDatabase.Wrap(errBind)
	}
	return logs, page.NewPageResult(pageParam.PageSize, pageParam.PageIndex, total), nil
}

//GetRobotsLogsFromDB 从数据库获得机器人日志
func (m *LogManager) GetRobotsLogsFromDB(ctx context.Context, agvID string, from, end time.Time) ([]model.RobotLog, codes.Code) {
	if end.IsZero() {
		end = time.Now()
	}
	filter := bson.M{"created_at": bson.M{"$gte": from, "$lte": end}}
	if agvID != "" {
		filter["agv_id"] = agvID
	}
	dbRes, err := m.db.Collection(ctx, model.RobotLog{}.TableName()).Find(ctx, filter)
	if err != nil {
		log.ErrorfWithContext(ctx, "get robot logs from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(err)
	}
	logs := make([]model.RobotLog, 0)
	if errBind := dbRes.All(ctx, &logs); errBind != nil {
		log.ErrorfWithContext(ctx, "bind robot logs from db error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return logs, nil
}

//StartAutoCleanDB 数据库自动清理
func (m *LogManager) StartAutoCleanDB(days int) {
	go func() {
		for {
			ctx := context.TODO()
			_, err := m.db.Collection(ctx, model.RMSLog{}.TableName()).DeleteMany(ctx, bson.M{"created_at": bson.M{"$lte": time.Now().Add(-time.Duration(days) * 24 * time.Hour)}})
			if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
				log.ErrorfWithContext(ctx, "delete rms log from db error:%s", err.Error())
			}
			_, err = m.db.Collection(ctx, model.RobotLog{}.TableName()).DeleteMany(ctx, bson.M{"created_at": bson.M{"$lte": time.Now().Add(-time.Duration(days) * 24 * time.Hour)}})
			if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
				log.ErrorfWithContext(ctx, "delete robot log from db error:%s", err.Error())
			}
			time.Sleep(1 * time.Hour)
		}
	}()
}
